package cn.klaw.i18n.provider;

import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import cn.klaw.base.UserInfo;
import cn.klaw.util.UserProvider;
import cn.klaw.config.ConfigValueUtil;
import cn.klaw.constant.GlobalConst;
import cn.klaw.constant.model.MCode;
import cn.klaw.util.TenantHolder;
import lombok.extern.slf4j.Slf4j;

import java.util.Locale;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 国际化语言翻译
 */
@Slf4j
public class MyI18nMessageProvider implements I18nMessageProvider {

    private ConfigValueUtil configValueUtil;

    private final long CACHE_TIME = 48 * 60 * 60000L;

    // 未使用的情况下, 默认48小时失效, 使用后重新计算缓存时效
    private TimedCache<String, TimedCache<String, Properties>> tenantMessageProperties = CacheUtil.newTimedCache(CACHE_TIME);
    // 翻译内容提供者
    private DynamicMessageProvider dynamicMessageProvider;
    // 租户语言加载锁
    private final ConcurrentHashMap<String, ReentrantLock> lockMap = new ConcurrentHashMap<>();
    private Properties emptyProperties = new Properties();

    public MyI18nMessageProvider(ConfigValueUtil configValueUtil, DynamicMessageProvider dynamicMessageProvider) {
        this.configValueUtil = configValueUtil;
        this.dynamicMessageProvider = dynamicMessageProvider;
        // 执行定时清理
        tenantMessageProperties.schedulePrune(CACHE_TIME);
    }

    public void removeTenantCache(String tenantId) {
        tenantMessageProperties.remove(tenantId);
    }

    public void loadTenantMessage(String tenantId, Locale locale) {
        Properties i18nListProperties = dynamicMessageProvider.getI18nListProperties(locale);
        TimedCache<String, Properties> tenantProperties = tenantMessageProperties.get(tenantId);
        if (tenantProperties == null) {
            tenantProperties = CacheUtil.newTimedCache(CACHE_TIME);
            tenantMessageProperties.put(tenantId, tenantProperties);
        }
        if (i18nListProperties == null) {
            // 语言加载失败, 一分钟后重新加载, 避免高频请求
            tenantProperties.put(locale.toLanguageTag(), emptyProperties, 60000L);
        } else {
            // 无论是否有内容返回都是加载成功, 如果properties为空没有翻译数据, 服务端新增翻译时会清空缓存重新加载
            tenantProperties.put(locale.toLanguageTag(), i18nListProperties);
        }
    }

    @Override
    public MCode getI18nMessage(String code, Locale locale) {
        UserInfo userInfo = UserProvider.getUser();
        // 未登录不获取
        if (userInfo.getToken() == null) {
            return null;
        }
        // 默认租户或者当前租户
        String tenantId = GlobalConst.DEFAULT_TENANT_VALUE;
        if (configValueUtil.isMultiTenancy()) {
            tenantId = TenantHolder.getDatasourceId();
        }
        // 开启租户未获取到租户 不进行翻译获取
        if (tenantId != null) {
            // 租户配置中的语言配置
            String languageTag = locale.toLanguageTag();
            if (!tenantMessageProperties.containsKey(tenantId) || !tenantMessageProperties.get(tenantId).containsKey(languageTag)) {
                // 租户其他线程正在加载多语言则直接返回
                ReentrantLock lock = lockMap.computeIfAbsent(tenantId, k -> new ReentrantLock());
                boolean isLock = false;
                try {
                    isLock = lock.tryLock();
                    if (isLock) {
                        loadTenantMessage(tenantId, locale);
                    } else {
                        log.debug("[{}]语言加载中, 直接返回", tenantId);
                        return null;
                    }
                } finally {
                    if (isLock) {
                        lock.unlock();
                    }
                }
            }
            Properties languageProperty = tenantMessageProperties.get(tenantId).get(languageTag, false);
            if (languageProperty != null) {
                Object message = languageProperty.get(code);
                if (message != null) {
                    return new MCode("", code, message.toString());
                }
            }
        }
        return null;
    }
}
